package cn.edu.sgu.www.mhxysy.function.computer.score.impl;

import cn.edu.sgu.www.mhxysy.entity.chongwu.*;
import cn.edu.sgu.www.mhxysy.entity.chongwu_equipment.ChongwuEquipment;
import cn.edu.sgu.www.mhxysy.entity.chongwu_equipment.ChongwuEquipmentAttribute;
import cn.edu.sgu.www.mhxysy.entity.chongwu_equipment.ChongwuTaozhuangSkill;
import cn.edu.sgu.www.mhxysy.entity.chongwu_equipment.ChongwuWaiguan;
import cn.edu.sgu.www.mhxysy.entity.wenshi.Wenshi;
import cn.edu.sgu.www.mhxysy.entity.wenshi.WenshiCategory;
import cn.edu.sgu.www.mhxysy.entity.wenshi.ZuoqiWenshi;
import cn.edu.sgu.www.mhxysy.entity.xingshi.Xingshi;
import cn.edu.sgu.www.mhxysy.entity.chongwu_shizhuang.ChongwuShizhuang;
import cn.edu.sgu.www.mhxysy.entity.zuoqi.ZuoqiChongwu;
import cn.edu.sgu.www.mhxysy.enums.ChongwuEquipmentAttributeTypes;
import cn.edu.sgu.www.mhxysy.enums.NeidanTypes;
import cn.edu.sgu.www.mhxysy.enums.TongyuStatus;
import cn.edu.sgu.www.mhxysy.enums.WearStatus;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.function.computer.score.ScoreComputer;
import cn.edu.sgu.www.mhxysy.mapper.chongwu.*;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_equipment.ChongwuEquipmentAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_equipment.ChongwuEquipmentMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_equipment.ChongwuTaozhuangSkillMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_equipment.ChongwuWaiguanMapper;
import cn.edu.sgu.www.mhxysy.mapper.wenshi.WenshiCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.wenshi.WenshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.wenshi.ZuoqiWenshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingshi.XingshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.chongwu_shizhuang.ChongwuShizhuangMapper;
import cn.edu.sgu.www.mhxysy.mapper.zuoqi.ZuoqiChongwuMapper;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 宠物评分计算器
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Slf4j
@Component
public class ChongwuScoreComputer implements ScoreComputer {

    private final WenshiMapper wenshiMapper;
    private final ChongwuMapper chongwuMapper;
    private final XingshiMapper xingshiMapper;
    private final ZuoqiWenshiMapper zuoqiWenshiMapper;
    private final ChongwuSkillMapper chongwuSkillMapper;
    private final ChongwuZizhiMapper chongwuZizhiMapper;
    private final ZuoqiChongwuMapper zuoqiChongwuMapper;
    private final ChongwuNeidanMapper chongwuNeidanMapper;
    private final ChongwuWaiguanMapper chongwuWaiguanMapper;
    private final WenshiCategoryMapper wenshiCategoryMapper;
    private final ChongwuEquipmentMapper chongwuEquipmentMapper;
    private final ChongwuShizhuangMapper chongwuShizhuangMapper;
    private final ChongwuSkillCategoryMapper chongwuSkillCategoryMapper;
    private final ChongwuNeidanCategoryMapper chongwuNeidanCategoryMapper;
    private final ChongwuTaozhuangSkillMapper chongwuTaozhuangSkillMapper;
    private final ChongwuNeidanResonanceMapper chongwuNeidanResonanceMapper;
    private final ChongwuEquipmentAttributeMapper chongwuEquipmentAttributeMapper;

    @Autowired
    public ChongwuScoreComputer(
            WenshiMapper wenshiMapper,
            ChongwuMapper chongwuMapper,
            XingshiMapper xingshiMapper,
            ZuoqiWenshiMapper zuoqiWenshiMapper,
            ChongwuSkillMapper chongwuSkillMapper,
            ChongwuZizhiMapper chongwuZizhiMapper,
            ZuoqiChongwuMapper zuoqiChongwuMapper,
            ChongwuNeidanMapper chongwuNeidanMapper,
            ChongwuWaiguanMapper chongwuWaiguanMapper,
            WenshiCategoryMapper wenshiCategoryMapper,
            ChongwuEquipmentMapper chongwuEquipmentMapper,
            ChongwuShizhuangMapper chongwuShizhuangMapper,
            ChongwuSkillCategoryMapper chongwuSkillCategoryMapper,
            ChongwuNeidanCategoryMapper chongwuNeidanCategoryMapper,
            ChongwuTaozhuangSkillMapper chongwuTaozhuangSkillMapper,
            ChongwuNeidanResonanceMapper chongwuNeidanResonanceMapper,
            ChongwuEquipmentAttributeMapper chongwuEquipmentAttributeMapper) {
        this.wenshiMapper = wenshiMapper;
        this.chongwuMapper = chongwuMapper;
        this.xingshiMapper = xingshiMapper;
        this.chongwuSkillMapper = chongwuSkillMapper;
        this.chongwuZizhiMapper = chongwuZizhiMapper;
        this.zuoqiWenshiMapper = zuoqiWenshiMapper;
        this.zuoqiChongwuMapper = zuoqiChongwuMapper;
        this.chongwuNeidanMapper = chongwuNeidanMapper;
        this.chongwuWaiguanMapper = chongwuWaiguanMapper;
        this.wenshiCategoryMapper = wenshiCategoryMapper;
        this.chongwuEquipmentMapper = chongwuEquipmentMapper;
        this.chongwuShizhuangMapper = chongwuShizhuangMapper;
        this.chongwuSkillCategoryMapper = chongwuSkillCategoryMapper;
        this.chongwuNeidanCategoryMapper = chongwuNeidanCategoryMapper;
        this.chongwuTaozhuangSkillMapper = chongwuTaozhuangSkillMapper;
        this.chongwuNeidanResonanceMapper = chongwuNeidanResonanceMapper;
        this.chongwuEquipmentAttributeMapper = chongwuEquipmentAttributeMapper;
    }

    /**
     * 计算宠物总评分
     * @param chongwuId 宠物ID
     * @return Integer 宠物评分
     */
    @Override
    public Integer apply(String chongwuId) {
        Chongwu chongwu = chongwuMapper.selectById(chongwuId);

        if (chongwu == null) {
            throw new GlobalException(ResponseCode.CONFLICT, "操作失败，宠物不存在！");
        }

        /*
         * 宠物评分 = 内部评分（宠物自身的评分） + 外部评分（宠物装备 + 纹饰 + 时装）
         */
        AtomicInteger score = new AtomicInteger();

        /*
         * 内部评分 = 资质评分 + 技能评分 + 内丹评分
         */
        score.addAndGet(computeInnerScore(chongwuId));

        /*
         * 外部评分 = 宠物装备 + 时装 + 纹饰
         */
        score.addAndGet(computeOuterScore(chongwu));

        log.debug("宠物{}的总评分为：{}", chongwu.getId(), score.get());

        return score.get();
    }

    /**
     * 计算宠物内部评分
     * @param chongwuId 宠物ID
     * @return int 宠物的内部评分
     */
    private int computeInnerScore(String chongwuId) {
        /*
         * 内部评分 = 宠物资质评分 + 宠物技能评分 + 宠物内丹评分
         */
        AtomicInteger score = new AtomicInteger();

        score.addAndGet(computeScoreOfZizhi(chongwuId));
        score.addAndGet(computeScoreOfSkill(chongwuId));
        score.addAndGet(computeScoreOfNeidan(chongwuId));

        log.debug("宠物{}的内部评分为：{}", chongwuId, score.get());

        return score.get();
    }

    /**
     * 计算宠物外部评分
     * @param chongwu Chongwu
     * @return int 宠物的内部评分
     */
    private int computeOuterScore(Chongwu chongwu) {
        // 得到宠物ID
        String chongwuId = chongwu.getId();

        /*
         * 外部评分 = 装备评分 + 套装评分 + 外观附加属性评分 + 纹饰评分 + 时装评分
         */
        AtomicInteger score = new AtomicInteger();

        /*
         * 1、装备评分（装备 + 星石) + 外观附加属性评分
         */
        Map<String, Object> columnMap = new HashMap<>();

        columnMap.put("chongwu_id", chongwuId);
        columnMap.put("wear_status", WearStatus.YCD.getValue());

        List<ChongwuEquipment> chongwuEquipments = chongwuEquipmentMapper.selectByMap(columnMap);

        if (CollectionUtils.isNotEmpty(chongwuEquipments)) {
            chongwuEquipments.forEach(new Consumer<ChongwuEquipment>() {
                @Override
                public void accept(ChongwuEquipment equipment) {
                    // 1.1、装备评分
                    score.addAndGet(equipment.getScore());

                    // 得到宠物装备ID
                    String equipmentId = equipment.getId();

                    /*
                     * 1.2、装备外观属性评分
                     */
                    // 查询宠物装备的外观追加属性
                    columnMap.clear();
                    columnMap.put("equipment_id", equipmentId);
                    columnMap.put("type", ChongwuEquipmentAttributeTypes.WGZJ.getValue());

                    List<ChongwuEquipmentAttribute> list = chongwuEquipmentAttributeMapper.selectByMap(columnMap);

                    // 累加外观属性评分
                    if (CollectionUtils.isNotEmpty(list)) {
                        for (ChongwuEquipmentAttribute equipmentAttribute : list) {
                            score.addAndGet(equipmentAttribute.getPropertyValue() * 2);
                        }
                    }

                    /*
                     * 1.3、星石评分
                     */
                    // 查询宠物装备镶嵌的星石
                    QueryWrapper<Xingshi> queryWrapper = new QueryWrapper<>();

                    queryWrapper.eq("equipment_id", equipmentId);

                    Xingshi xingshi = xingshiMapper.selectOne(queryWrapper);

                    if (xingshi != null) {
                        score.addAndGet(xingshi.getScore());
                    }
                }
            });

            log.debug("宠物{}的装备评分：{}", chongwuId, score.get());

            // 查询宠物装备的外观效果
            columnMap.clear();
            columnMap.put("chongwu_id", chongwuId);

            List<ChongwuWaiguan> list = chongwuWaiguanMapper.selectByMap(columnMap);

            if (list.size() > 0) {
                if (list.size() == 1) {
                    // 宠物外观-增加60评分
                    score.addAndGet(60);

                    log.debug("宠物{}的外观评分：{}", chongwuId, 60);
                } else {
                    throw new GlobalException(ResponseCode.CONFLICT, "数据异常，宠物{" + chongwuId + "}激活了多个外观效果！");
                }
            }
        }

        /*
         * 2、套装评分
         */
        QueryWrapper<ChongwuTaozhuangSkill> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("chongwu_id", chongwuId);

        Long count = chongwuTaozhuangSkillMapper.selectCount(queryWrapper);

        if (count > 0) {
            if (count == 1) {
                score.addAndGet(60);

                log.debug("宠物{}的套装评分：{}", chongwuId, 60);
            } else {
                throw new GlobalException(ResponseCode.CONFLICT, "数据异常，宠物{" + chongwuId + "}激活了多个套装技能！");
            }
        }

        /*
         * 3、纹饰评分
         */
        // 宠物的统御状态为1-统御中
        if (TongyuStatus.YTY.getValue().equals(chongwu.getTongyuStatus())) {
            // 通过宠物ID查询坐骑-宠物
            columnMap.clear();
            columnMap.put("chongwu_id", chongwuId);

            List<ZuoqiChongwu> list = zuoqiChongwuMapper.selectByMap(columnMap);

            if (CollectionUtils.isNotEmpty(list)) {
                for (ZuoqiChongwu zuoqiChongwu : list) {
                    columnMap.clear();
                    columnMap.put("zuoqi_id", zuoqiChongwu.getZuoqiId());

                    List<ZuoqiWenshi> zuoqiWenshis = zuoqiWenshiMapper.selectByMap(columnMap);

                    if (CollectionUtils.isNotEmpty(zuoqiWenshis)) {
                        for (ZuoqiWenshi zuoqiWenshi : zuoqiWenshis) {
                            String wenshiId = zuoqiWenshi.getWenshiId();
                            Wenshi wenshi = wenshiMapper.selectById(wenshiId);
                            WenshiCategory wenshiCategory = wenshiCategoryMapper.selectById(wenshi.getCategoryId());

                            // 纹饰的评分 = （2 ^ 纹饰等级） * 10
                            score.addAndGet((1 << wenshiCategory.getGrade()) * 10);
                        }
                    }
                }
            }
        }

        /*
         * 5、月华幻衣评分
         */
        columnMap.clear();
        columnMap.put("chongwu_id", chongwuId);
        columnMap.put("wear_status", WearStatus.YCD.getValue());

        List<ChongwuShizhuang> list = chongwuShizhuangMapper.selectByMap(columnMap);

        if (list.size() > 0) {
            if (list.size() == 1) {
                ChongwuShizhuang chongwuShizhuang = list.get(0);

                score.addAndGet(chongwuShizhuang.getScore());
            } else {
                throw new GlobalException(ResponseCode.CONFLICT, "数据异常，宠物{" + chongwuId + "}穿戴了多件月华时装！");
            }
        }

        log.debug("宠物{}的外部评分为：{}", chongwuId, score);

        return score.get();
    }

    /**
     * 计算宠物资质成长评分
     * @param chongwuId 宠物ID
     * @return int 宠物的资质评分
     */
    private int computeScoreOfZizhi(String chongwuId) {
        /*
         * 资质评分 = (攻击资质 ÷ 10) + (防御资质 ÷ 10) + (体力资质 * 28 ÷ 1000) + (法力资质 ÷ 20) + (速度资质 ÷ 10) + (成长 * 72 ÷ 100)
         */
        AtomicInteger score = new AtomicInteger();

        // 查询宠物资质
        QueryWrapper<ChongwuZizhi> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("chongwu_id", chongwuId);

        ChongwuZizhi chongwuZizhi = chongwuZizhiMapper.selectOne(queryWrapper);

        if (chongwuZizhi != null) {
            // 攻击资质 / 10
            score.addAndGet(chongwuZizhi.getGjzz() / 10);

            // 防御资质 / 10
            score.addAndGet(chongwuZizhi.getFyzz() / 10);

            // 体力资质 * 28 / 1000
            BigDecimal decimal = new BigDecimal(chongwuZizhi.getTlzz());

            decimal = decimal.multiply(new BigDecimal(28));
            decimal = decimal.divide(new BigDecimal(1000), MathContext.UNLIMITED);

            score.addAndGet((int) Math.ceil(decimal.floatValue()));

            // 法力资质 / 20
            score.addAndGet(chongwuZizhi.getFlzz() / 20);

            // 速度资质 / 10
            score.addAndGet(chongwuZizhi.getSdzz() / 10);

            // 成长 * 72 / 100
            decimal = new BigDecimal(chongwuZizhi.getChengzhang());

            decimal = decimal.multiply(new BigDecimal(72));
            decimal = decimal.divide(new BigDecimal(100), MathContext.UNLIMITED);

            score.addAndGet((int) Math.ceil(decimal.floatValue()));
        }

        log.debug("宠物{}的资质评分为：{}", chongwuId, score.get());

        return score.get();
    }

    /**
     * 计算宠物技能评分
     * @param chongwuId 宠物ID
     * @return int 宠物的技能评分
     */
    private int computeScoreOfSkill(String chongwuId) {
        AtomicInteger score = new AtomicInteger(0);

        // 查询宠物学习的所有技能
        Map<String, Object> columnMap = new HashMap<>();

        columnMap.put("chongwu_id", chongwuId);

        List<ChongwuSkill> chongwuSkills = chongwuSkillMapper.selectByMap(columnMap);

        if (CollectionUtils.isNotEmpty(chongwuSkills)) {
            // 得到所有的宠物技能类型ID
            Stream<ChongwuSkill> stream = chongwuSkills.stream();
            List<Integer> skillIds = stream.map(new Function<ChongwuSkill, Integer>() {
                @Override
                public Integer apply(ChongwuSkill chongwuSkill) {
                    return chongwuSkill.getSkillId();
                }
            }).collect(Collectors.toList());

            // 通过in子句查询
            QueryWrapper<ChongwuSkillCategory> queryWrapper = new QueryWrapper<>();

            queryWrapper.in("id", skillIds);

            List<ChongwuSkillCategory> list = chongwuSkillCategoryMapper.selectList(queryWrapper);

            // 累加所有宠物技能的评分
            for (ChongwuSkillCategory chongwuSkillCategory : list) {
                // 评分 += 宠物技能评分
                score.addAndGet(chongwuSkillCategory.getScore());
            }
        }

        log.debug("宠物{}的技能评分为：{}", chongwuId, score.get());

        return score.get();
    }

    /**
     * 计算宠物内丹评分
     * @param chongwuId 宠物ID
     * @return int 宠物的内丹评分
     */
    private int computeScoreOfNeidan(String chongwuId) {
        /*
         * 内丹评分 = 低级内丹评分 + 高级内丹评分 + 专属内丹评分 + 内丹共鸣评分
         * 1、低级内丹 = 24 + 内丹等级 * 8
         * 2、高级内丹 = 72 + 内丹等级 * 24
         * 3、专属内丹 = 72 + 内丹等级 * 24
         * 4、共鸣评分 = 共鸣内丹的个数 * 32
         */
        AtomicInteger score = new AtomicInteger();

        // 查询所有宠物内丹
        QueryWrapper<ChongwuNeidan> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("chongwu_id", chongwuId);

        List<ChongwuNeidan> list = chongwuNeidanMapper.selectList(queryWrapper);

        if (CollectionUtils.isNotEmpty(list)) {
            for (ChongwuNeidan chongwuNeidan : list) {
                ChongwuNeidanCategory chongwuNeidanCategory = chongwuNeidanCategoryMapper.selectById(chongwuNeidan.getNeidanId());
                // 内丹类型
                Integer type = chongwuNeidanCategory.getType();
                // 内丹层数
                Integer grade = chongwuNeidan.getGrade();

                if (NeidanTypes.DJND.getValue().equals(type)) { // 低级内丹
                    score.addAndGet(24 + grade * 8);
                } else if (NeidanTypes.GJND.getValue().equals(type) || NeidanTypes.ZSND.getValue().equals(type)) { // 高级内丹/专属内丹
                    score.addAndGet(72 + grade * 24);

                    // 高级内丹考虑共鸣
                    if (NeidanTypes.GJND.getValue().equals(type)) {
                        // 查询产生共鸣的内丹数量
                        int count = chongwuNeidanResonanceMapper.selectResonanceCount(chongwuId, chongwuNeidan.getId());

                        // 评分 += 共鸣数量 * 32
                        if (count > 0) {
                            score.addAndGet(count * 32);
                        }
                    }
                } else {
                    throw new GlobalException(ResponseCode.BAD_REQUEST, "非法的内丹类型：" + type);
                }
            }
        }

        log.debug("宠物{}的内丹评分为：{}", chongwuId, score.get());

        return score.get();
    }

}